package com.gitee.wsl.serialization.json

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
 * KSerializer that can serialize/deserialize optional scalar values.
 */
object OptionalSerializer : KSerializer<OptionalInput<Any>> {

    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("OptionalScalar")

    override fun serialize(encoder: Encoder, value: OptionalInput<Any>) {
        when (value) {
            is OptionalInput.Undefined -> { return }
            is OptionalInput.Defined<*> -> {
                AnyKSerializer.serialize(encoder, value.value)
            }
        }
    }

    // undefined is only supported during client serialization
    override fun deserialize(decoder: Decoder): OptionalInput<Any> = OptionalInput.Defined(
        AnyKSerializer.deserialize(decoder)
    )
}


sealed class OptionalInput<out T> {
    /**
     * Represents missing/undefined value.
     */
    object Undefined : OptionalInput<Nothing>() {
        override fun toString() = "UNDEFINED"
    }

    /**
     * Wrapper holding explicitly specified value including NULL.
     */
    data class Defined<out U>(val value: U?) : OptionalInput<U>() {
        override fun toString(): String = "Defined(value=$value)"
    }
}